package com.credithc.signature.job.handler;

import com.credithc.signature.common.mapper.ChannelMapper;
import com.credithc.signature.common.mapper.ProductSignMapper;
import com.credithc.signature.common.po.Channel;
import com.credithc.signature.common.po.ProductSign;
import com.credithc.signature.job.configure.props.SignatureProps;
import com.credithc.signature.job.ro.CallRequest;
import com.credithc.signature.job.ro.HandleRequest;
import com.credithc.signature.job.ro.JobRequest;
import com.credithc.signature.job.service.signprovide.SignatureProvider;
import com.credithc.signature.job.utils.BeanUtil;
import com.credithc.signature.job.utils.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @desc: <br/>
 * @author: Jingbo Hu<br/>
 * @time：2021年06⽉25⽇<br/>
 * @version：v1.0.0<br>
 */
@Slf4j
public class ProcessSignHandler extends AbstractExecuteHandler {

    private String handlerName = "合同签章";

    @Autowired
    private static SignatureProps props;

    @Autowired
    private static ProductSignMapper productSignMapper;

    @Autowired
    private static ChannelMapper channelMapper;

    static {
        channelMapper = SpringUtil.getBean(ChannelMapper.class);
        productSignMapper = SpringUtil.getBean(ProductSignMapper.class);
        props = SpringUtil.getBean(SignatureProps.class);
    }


    /**
     * 设置HandlerName
     */
    public ProcessSignHandler() {
        this.handlerName = handlerName;
    }


    @Override
    public void handleRequest(HandleRequest handleRequest) throws Exception {
        if (Objects.nonNull(handleRequest)) {
            JobRequest jobRequest = handleRequest.getJobRequest();
            String requestSn = jobRequest.getRequestSn();
            try {
                // 1、执行签章
                String pdfPath = signatureAndResumption(handleRequest.getJobRequest(), handleRequest.getCertInfos(), handleRequest.getPdfPath(), handleRequest.getSealCodes());
                handleRequest.setPdfPath(pdfPath);
                log.info("－消息－:requestSn={},【{}】已经处理;流程结束", requestSn, handlerName);

                // 2、判断是否有下一个
                hasNextHandler(requestSn, handleRequest);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("－消息－:requestSn={},执行【{}】流程时发生异常;总流程结束\n{}", requestSn, handlerName, e.getCause());
                this.setNextHandler(new CallbackHandler());
                CallRequest callRequest = new CallRequest();
                BeanUtils.copyProperties(jobRequest,callRequest);
                callRequest.setCallBackURL(jobRequest.getCallbackUrl());
                callRequest.setRequestSN(requestSn);
                callRequest.setIsSuccess(false);
                callRequest.setErrorMsg(e.getMessage());
                handleRequest.setCallRequest(callRequest);
                this.nextHandler.handleRequest(handleRequest);
            }
        }
    }

    /**
     * 判断是否还有下一个流程:如果有，则继续执行
     */
    private void hasNextHandler(String requestSn, HandleRequest handleRequest) throws Exception {
        if (null != this.nextHandler) {
            this.nextHandler.handleRequest(handleRequest);
        } else {
            log.info("－消息－:requestSn={},【{}】无下一个执行流程;总流程结束", requestSn, handlerName);
            return;
        }
    }

    /**
     * 查询签章三方，并执行签章逻辑
     *
     * @param coreRequet
     * @param certInfos
     * @param pdfPath
     * @param sealCodes
     * @return
     * @throws Exception
     */
    private String signatureAndResumption(JobRequest coreRequet, List<Map<String, String>> certInfos, String pdfPath, List<String> sealCodes) throws Exception {
        if (coreRequet.getNeedSign()) {
            long startSign = System.currentTimeMillis();
            String requestSn = coreRequet.getRequestSn();
            for (int signatureTryCount = 0; signatureTryCount <= props.signatureTryTimes; signatureTryCount++) {
                try {
                    // 签章逻辑
                    pdfPath = sign(coreRequet, pdfPath, certInfos, sealCodes);
                    break;
                } catch (Exception e) {
                    if (signatureTryCount >= props.signatureTryTimes) {
                        throw new RuntimeException(e);
                    }
                }
            }
            long endSign = System.currentTimeMillis();
            log.debug("－消息－: requestSn={},签章总耗时:{}毫秒", coreRequet.getRequestSn(), (endSign - startSign));
        }
        return pdfPath;
    }

    /**
     * 执行签章
     *
     * @param coreRequet
     * @param pdfPath
     * @param certInfos
     * @param sealCodes
     * @return
     * @throws Exception
     */
    public String sign(JobRequest coreRequet, String pdfPath, List<Map<String, String>> certInfos, List<String> sealCodes) throws Exception {
        Channel channel;
        Example example = new Example(Channel.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("channelMappingNo", coreRequet.getChannelNo());
        channel = channelMapper.selectOneByExample(example);
        if (channel == null) {
            channel = channelMapper.selectByChannelNo(coreRequet.getChannelNo());
        }

        Example pse = new Example(ProductSign.class);
        Example.Criteria psec = pse.createCriteria();
        psec.andEqualTo("productCode", channel.getChannelNo());
        List<ProductSign> productSigns = productSignMapper.selectByExample(pse);

        // 1、未配置默认中金
        if (productSigns == null || productSigns.isEmpty()) {
            log.debug("－消息－: requestSn={},未配置路由,默认【中金】签章", coreRequet.getRequestSn());
            SignatureProvider provider = BeanUtil.getBean("zjSignature", SignatureProvider.class);
            return provider.processSignature(coreRequet, pdfPath, certInfos, sealCodes);
        }
        // 2、按照分配比例走
        long vernier = System.currentTimeMillis() % 100;
        int vs = 0;
        for (ProductSign ps : productSigns) {
            vs += ps.getPercentage();
            if (vernier < vs) {
                log.debug("－消息－: requestSn={},根据配比执行【{}】签章", coreRequet.getRequestSn(), ps.getThirdPartyName());
                SignatureProvider provider = BeanUtil.getBean(ps.getMethodName(), SignatureProvider.class);
                return provider.processSignature(coreRequet, pdfPath, certInfos, sealCodes);
            }
        }
        return null;
    }
}
